package pl.msikora.android.lapmagic.view;

import pl.msikora.android.lapmagic.R;
import pl.msikora.android.lapmagic.database.LapMagicDatabaseHelper;
import pl.msikora.android.lapmagic.database.PointsTable;
import pl.msikora.android.lapmagic.database.TracksTable;
import pl.msikora.android.lapmagic.view.overlay.PointOverlayItem;
import pl.msikora.android.lapmagic.view.overlay.TrackItemizedOverlay;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockMapActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;

/**
 * View representing a track on a map with its points and attributes.
 * 
 * This view enables editing and deleting track
 * 
 * @author Maciej Sikora
 * 
 */
public class TrackDetailActivity extends SherlockMapActivity {
	
	private final String TAG = "TrackDetailActivity";
	
	private long track_id = -1;
	private String track_name = null;
	private boolean deleteMode = false;
	private MapView map = null;
	private TrackItemizedOverlay itemizedOverlay = null;
	private View trackNameActionView = null;

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Bundle extras = getIntent().getExtras();
		if (extras != null) {
			track_id = extras.getLong("id");
			Log.d(TAG, "retrieved track id " + track_id);
		}
				
		// basic layout
		setContentView(R.layout.track_detail);
		ActionBar actionBar = getSupportActionBar();
		actionBar.setHomeButtonEnabled(true);
		actionBar.setTitle(R.string.track_detail_title);
		map = (MapView) findViewById(R.id.mapView);
		map.setBuiltInZoomControls(true);
		map.setSatellite(true);
		map.getController().setZoom(17);
		
		Drawable drawable = getResources()
				.getDrawable(R.drawable.androidmarker);
		ImageView dragImage = (ImageView) findViewById(R.id.drag);
		itemizedOverlay = new TrackItemizedOverlay(drawable, dragImage, this);
		
		if (track_id != -1) {
			setTrackName();
			setTrackOverlay();
		}
		else
			track_name = getString(R.string.track_detail_new);
		
		map.getOverlays().add(itemizedOverlay);
		setMapView();
		Toast.makeText(this, track_name, Toast.LENGTH_LONG).show();
	}
	
	@Override
	public void onPause() {
		
		boolean nameHasChanged = false;

		/*
		 * On fast double rotation this action view is set to null.
		 * In that moment we have correct value in this.track_name so leave it
		 * that way.
		 */
		if (trackNameActionView != null) {
			EditText name = (EditText) trackNameActionView
					.findViewById(R.id.trackEditText);
			String newNameText = name.getText().toString();
			if (!newNameText.equals(track_name)) {
				track_name = newNameText;
				nameHasChanged = true;
			}
		}
		
		SQLiteDatabase db = LapMagicDatabaseHelper.getInstance(this)
				.getWritableDatabase();

		ContentValues trackValues = new ContentValues();
		trackValues.put(TracksTable.COLUMN_NAME, track_name);

		if (!deleteMode) {
			
			// a new track - insert everything
			if (track_id == -1) {
				Log.d(TAG, "inserting new track " + track_name);
				track_id = db.insert(TracksTable.TABLE_TRACKS, null,
						trackValues);
				for (PointOverlayItem point : itemizedOverlay.getOverlays()) {
					Log.d(TAG, "inserting new point " + point.getName()
							+ " of type " + point.getType());
					insertPoint(point, db);
				}
				
				Toast.makeText(this, getString(R.string.track_detail_saving)
					+ " " + track_name, Toast.LENGTH_SHORT).show();
			}
			// update existing track
			else {
				Log.d(TAG, "updating track " + track_name);
				if (nameHasChanged) {
					Log.d(TAG, "updating track name to " + track_name);
					db.update(TracksTable.TABLE_TRACKS, trackValues, "_id = "
						+ track_id, null);
				}
				
				for (PointOverlayItem point : itemizedOverlay.getOverlays()) {
					if (point.getId() == -1)  { // a new point
						Log.d(TAG, "inserting new point " + point.getName()
								+ " of type " + point.getType());						
						insertPoint(point, db);
					}
					else if (point.hasChanged()) { // update existing
						Log.d(TAG, "updating point name to " + point.getName()
								+ ", type to " + point.getType());						
						updatePoint(point, db);
					}
				}
			}
		}
		// delete existing track, ignore a new one, points are handled by trigger
		else if (track_id != -1) {
    		Toast.makeText(this, getString(R.string.track_detail_deleting) + " "
    			+ track_name, Toast.LENGTH_LONG).show();
    		Log.d(TAG, "deleting track " + track_name);
			db.delete(TracksTable.TABLE_TRACKS, "_id = " + track_id, null);
			deleteMode = false;
		}
		super.onPause();
	}
	
	@Override
	public void onStop() {
		Intent intent = getIntent();
		
		/* If we're creating new track and we're changing orientation, we save
		 * track_id in the intent to restore it during the restart
		 * of this activity instance.
		 * We're not using onSaveInstanceState(Bundle) because on different
		 * machines it is sometimes fired after and sometimes before onPause(),
		 * where we save the track in database.
		 */
		if (intent.getExtras() == null) {
			intent.putExtra("id", track_id);
			Log.d(TAG, "saving track id " + track_id 
					+ " of newly created track");
		}
		super.onStop();
	}
		
	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.track_detail_menu, menu);
        
        // set the appropriate track name at menu bar
        trackNameActionView = (View) menu.findItem(R.id.trackName)
        		.getActionView();
        EditText name = (EditText) trackNameActionView
        		.findViewById(R.id.trackEditText);
        name.setText(track_name);
        return true;
    }
	
	@Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	switch (item.getItemId()) {
    	case android.R.id.home:
    		Intent home = new Intent(this, MainActivity.class);
    		home.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    		startActivity(home);
    		return true;
    	
    	case R.id.newPoint:
    		GeoPoint center = map.getMapCenter();
    		PointOverlayItem overlayitem =
    				new PointOverlayItem(center,
    						getString(R.string.track_detail_point_name_default),
    						getString(R.string.track_detail_point_type_default));
    		Log.d(TAG, "created new point '" + overlayitem.getName()
    				+ "' of type '" + overlayitem.getType() + "'");
    		itemizedOverlay.addOverlay(overlayitem);
    		map.invalidate();
    		Toast.makeText(this, R.string.track_detail_new_point,
    				Toast.LENGTH_SHORT).show();
    		return true;
    		
    	case R.id.movePoints:
    		int messageId;
    		
    		// switch the drag mode
    		if (itemizedOverlay.isDragModeEnabled()) {
    			messageId = R.string.track_detail_drag_off;
    			itemizedOverlay.disableDragMode();
    		}
    		else {
    			messageId = R.string.track_detail_drag_on;
    			itemizedOverlay.enableDragMode();
			}		
    		Toast.makeText(this, messageId, Toast.LENGTH_LONG).show();
    		return true;
    	
    	case R.id.deleteTrack:
    		AlertDialog.Builder builder = new AlertDialog.Builder(this);
    		builder.setTitle(R.string.alert_dialog_delete_title)
    			.setMessage(R.string.alert_dialog_delete_track)
    			.setPositiveButton(R.string.alert_dialog_yes,
    					new OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
			    		Log.d(TAG, "switching delete mode ON");
			    		deleteMode = true;
			    		finish();
					}
				})
				.setNegativeButton(R.string.alert_dialog_cancel,
						new OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.cancel();
					}
				});
    		builder.create().show();
    		return true;
    	}

    	return super.onOptionsItemSelected(item);
    }
	
	private void setTrackName() {
		SQLiteDatabase db = LapMagicDatabaseHelper.getInstance(this)
				.getReadableDatabase();
		Cursor trackCursor = db.query(TracksTable.TABLE_TRACKS, new String[] {
				TracksTable.COLUMN_NAME }, TracksTable.COLUMN_ID + " = "
				+ track_id, null, null, null, null);
		trackCursor.moveToFirst();
		String name = trackCursor.getString(trackCursor
					.getColumnIndexOrThrow(TracksTable.COLUMN_NAME));
		Log.d(TAG, "setting track name = " + name);
		track_name = name;
		trackCursor.close();
	}
	
	private void setTrackOverlay() {
		SQLiteDatabase db = LapMagicDatabaseHelper.getInstance(this)
				.getReadableDatabase();
		Cursor pointCursor = db.query(PointsTable.TABLE_POINTS, new String[] {
				PointsTable.COLUMN_LATITUDE, PointsTable.COLUMN_LONGITUDE,
				PointsTable.COLUMN_NAME, PointsTable.COLUMN_TYPE,
				PointsTable.COLUMN_ID, PointsTable.COLUMN_RADIUS },
				PointsTable.COLUMN_TRACK_ID + " = " + track_id, null, null,
				null, null);
		
		for (pointCursor.moveToFirst(); !pointCursor.isAfterLast(); 
				pointCursor.moveToNext()) {
			
			int latitude = pointCursor.getInt(pointCursor
					.getColumnIndexOrThrow(PointsTable.COLUMN_LATITUDE));
			int longitude = pointCursor.getInt(pointCursor
					.getColumnIndexOrThrow(PointsTable.COLUMN_LONGITUDE));
			String name = pointCursor.getString(pointCursor
					.getColumnIndexOrThrow(PointsTable.COLUMN_NAME));
			String type = pointCursor.getString(pointCursor
					.getColumnIndexOrThrow(PointsTable.COLUMN_TYPE));
			long point_id = pointCursor.getLong(pointCursor
					.getColumnIndexOrThrow(PointsTable.COLUMN_ID));			
			long radius = pointCursor.getLong(pointCursor
					.getColumnIndexOrThrow(PointsTable.COLUMN_RADIUS));
			
			GeoPoint geoPoint = new GeoPoint(latitude, longitude); 
			PointOverlayItem overlayItem = 
					new PointOverlayItem(geoPoint, name, type, point_id,
							radius);
			Log.d(TAG, "adding overlay item for track "
					+ track_name + " at latitude = " + latitude
					+ ", longitude = " + longitude + ", name = " + name 
					+ ", type = " + type + ", radius = " + radius);
			itemizedOverlay.addOverlay(overlayItem);
		}
		
		pointCursor.close();
	}
	
	private void setMapView() {
		MapController controller = map.getController();
		
		// navigate to defined point
		if (itemizedOverlay.size() > 0) {
			Log.d(TAG, "navigating to defined track point");
			controller.animateTo(itemizedOverlay.getItem(0)
					.getPoint());
		}
		// navigate to current location (if possible)
		else {
			LocationManager manager =
					(LocationManager) getSystemService(LOCATION_SERVICE);
			Log.d(TAG, "trying gps location provider");
			Location me = manager.getLastKnownLocation(LocationManager.
					GPS_PROVIDER);
			
			if (me == null) {
				// try another provider
				Log.d(TAG, "trying network location provider");
				me = manager.getLastKnownLocation(LocationManager
					.NETWORK_PROVIDER);
				if (me == null) {
					Log.d(TAG, "didn't get current location - default view");
					return;
				}
			}
			
			Log.d(TAG, "navigating to my current position");
			controller.animateTo(new GeoPoint((int) (me.getLatitude() * 1e6),
					(int) (me.getLongitude() * 1e6)));
		}
	}
	
	private void insertPoint(PointOverlayItem point, SQLiteDatabase db) {
		ContentValues pointValues = preparePointValues(point);
		db.insert(PointsTable.TABLE_POINTS, null, pointValues);
	}

	private void updatePoint(PointOverlayItem point, SQLiteDatabase db) {
		ContentValues pointValues = preparePointValues(point);
		db.update(PointsTable.TABLE_POINTS, pointValues, "_id = " 
				+ point.getId(), null);
	}
	
	private ContentValues preparePointValues(PointOverlayItem point) {
		ContentValues pointValues = new ContentValues();
		GeoPoint geoPoint = point.getPoint();
		pointValues.put(PointsTable.COLUMN_TRACK_ID, track_id);
		pointValues.put(PointsTable.COLUMN_LATITUDE,
				geoPoint.getLatitudeE6());
		pointValues.put(PointsTable.COLUMN_LONGITUDE,
				geoPoint.getLongitudeE6());
		pointValues.put(PointsTable.COLUMN_NAME, point.getName());
		pointValues.put(PointsTable.COLUMN_TYPE, point.getType());
		pointValues.put(PointsTable.COLUMN_RADIUS, point.getRadius());
		return pointValues;
	}
}
